// ActionScript file
import classes.Game;
import classes.User;

import components.Room;

import flash.events.NetStatusEvent;
import flash.media.Camera;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.net.SharedObject;
import flash.utils.getTimer;

import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.managers.PopUpManager;
        
public var track1Limits:Track1Limits = new Track1Limits();
public var track1DecoOver:Track1DecoOver = new Track1DecoOver();
public var track1:Track1 = new Track1();
private var latencies_dp:Array = new Array();
private var latenciesNumber:int = 0;

[Bindable] public var game:Game = new Game();
[Bindable] public var myuser:User;
[Bindable] public var myopponent:User;

[Bindable] public var rooms_dp:ArrayCollection = new ArrayCollection();
[Bindable] public var users_dp:ArrayCollection = new ArrayCollection();
[Bindable] public var nc:NetConnection;	
//public var server:String = "rtmp://192.168.1.10/voiture/";
public var server:String = "rtmp://87.98.136.204/voiture/"; 
    
public var camera:Camera;
public var mic:Microphone;
public var nsInGoing:NetStream,nsOutGoing:NetStream;
public var hisVideo:Video;
public var so_chat:SharedObject; 

public function latencyCallBack(username:String , number:int, timer:uint):void {
	if (myuser.username!=username) return;
	latenciesNumber++;
	if (latenciesNumber==10) {
		calculatelatency();
	} else {
		var latency:uint =  getTimer()-timer;
		latencies_dp.push(latency);
		so_chat.send("latencyCallBack" , myuser.username , latenciesNumber , getTimer());
		getTimer()
	}
}
public function calculatelatency():void {
	latencies_dp.sort();
	Game.latency = latencies_dp[4]; // take the average !
	info_txt.text="latency:"+Game.latency+" ms";	
}
public function startlatencyCalculation():void {
	so_chat.send("latencyCallBack",myuser.username,latenciesNumber,getTimer());
}

public function joinNewUser(obj:Object):void {
	addUser(obj.id , obj.username , obj.room , obj.sex , obj.webcam , obj.ip);
}
public function addUser(id:String , username:String, room:String, sex:String,webcam:String,ip:String):void {
	if (myuser.room!=room) return;
	var newUser:User = new User(id,username,sex,room,webcam);	
	users_dp.addItem(newUser);
}
private function createRoom():void {
	var win:Room = new Room();
	PopUpManager.addPopUp(win , this ,true);
	PopUpManager.bringToFront(win);
	PopUpManager.centerPopUp(win);	
}
private function getOpponent():User {
	var o:User;	
	for (var i:int=0;i<users_dp.length;i++)	{
		o=users_dp.getItemAt(i) as User;
		if (o.username != myuser.username) {
			return o ;		
			break;
		}
	}
	return null;
}

private function getUserByUsername(username:String):User {
	var o:User;	
	for (var i:int=0;i<users_dp.length;i++)	{
		o=users_dp.getItemAt(i) as User;
		if (o.username == username) {
			return o ;		
			break;
		}
	}
	return null;
}
private function getUserIndex(username:String):int {
	for (var i:int=0;i<users_dp.length;i++)	{
		if (users_dp.getItemAt(i).username==username) return i;
     }	
     return -1;
}
public function getUserList(obj:Object):void {
	var i:String,id:String,username:String,room:String,webcam:String,sex:String,ip:String;
	var j:int=0;
	for (i in obj) {
		id=obj[i].id;			
		username=obj[i].username;
		room=obj[i].room;
		room=obj[i].room;
		sex=obj[i].sex;
		ip=obj[i].ip;
		addUser(id,username,room,sex,webcam,ip);
		j++;
	}
}
public function receiveGlobalText(username:String , txt:String):void {
	chat_txt.verticalScrollPosition=chat_txt.maxVerticalScrollPosition;	
	chat_txt.htmlText+="<b>" + username + "</b>:"+txt+"<br>";
	chat_txt.verticalScrollPosition=chat_txt.maxVerticalScrollPosition;	
}

private function sendTxt():void {	
	var txt:String = input_txt.text;
	if (txt=="") return;
	so_chat.send("receiveGlobalText",myuser.username,txt);
	input_txt.text="";
}
public function removeuser(anuser:Object):void {
	var i:int = getUserIndex(anuser.username);
	if (i==-1) return
	var user:User = getUserByUsername(anuser.username);
	user.removeCar();
	users_dp.removeItemAt(i);
	if (Game.hasStarted) {
		game.over("You won because "+anuser.username+" has left !");
	}
}
public function roomChanged(obj:Object):void {
	var name:String;
	rooms_dp = new ArrayCollection();
	for (var i:String in obj) {
		var aroom:Object = new Object();
		aroom.numberOfUsers = obj[i].numberOfUsers;
		aroom.name = obj[i].name;
		aroom.isLocked = obj[i].isLocked;
		var label:String = obj[i].name + "(" + aroom.numberOfUsers + ")";
		if (aroom.isLocked) label+="*";
		aroom.label = label;	
		aroom.owner = 	obj[i].owner;		
		rooms_dp.addItem(aroom);		
	}
	if (getRoomByRoomName(myuser.room)!=null) {
		myuser.isRoomOwner = (myuser.username == getRoomByRoomName(myuser.room).owner);
	}
	
}
public function getRoomByRoomName(name:String):Object {
	var o:Object;	
	for (var i:int=0;i<rooms_dp.length;i++)	{
		o=rooms_dp.getItemAt(i);
		if (o.name == name) {
			return o ;			
			break;
		}
	}
	return null;
}

public function netStatusHandler(event:NetStatusEvent):void {
	createRoom_btn.enabled=nc.connected;
	switch (event.info.code) {
    case "NetConnection.Connect.Success":
    	prepareStreams();
    	
        break;
	default:
		nc.close();
		break;
	}
}
public function drawMicLevel(evt:TimerEvent):void {
	var ac:int=mic.activityLevel;
	micLevel.setProgress(ac,100);
}
public function streamStatus(e:NetStatusEvent):void {	
}		
public function testWebcam():void {
	camera=Camera.getCamera();
	if (camera!=null) {
		if (camera.muted) {
			Security.showSettings(SecurityPanel.DEFAULT);
		}		
		camera.setMode(320,240,10);
		myWebcam.attachCamera(camera);
	}
}	

public function onPlayStatus(info:Object):void {
}

public function watchUser():void {
	var username:String = users_list.selectedItem.username;
	nsInGoing.play(username);
	canvasWebcam.visible=true
}
public function prepareStreams():void {
	testWebcam();
	connect_btn.enabled = false;
	username_txt.enabled = false;
	nsOutGoing = new NetStream(nc); 
	mic=Microphone.getMicrophone(0);
	if(mic!=null) {
		mic.rate=22;
   	    var timer:Timer=new Timer(50);
   		timer.addEventListener(TimerEvent.TIMER, drawMicLevel);
		timer.start();
		nsOutGoing.attachAudio(mic);
	}
	if (camera!=null) {
		camera.setMode(320,240,12);
		camera.setQuality(0,90);
		camera.setKeyFrameInterval(10);
		myWebcam.attachCamera(camera);
		nsOutGoing.attachCamera(camera);
	}		
	nsOutGoing.publish(myuser.username);
    nsInGoing= new NetStream(nc);nsInGoing.client=this;      
	nsInGoing.addEventListener(NetStatusEvent.NET_STATUS,streamStatus);
            
	hisVideo = new Video( 160, 120 );
	hisWebcam.video=hisVideo;
	hisVideo.attachNetStream(nsInGoing);
	startlatencyCalculation();
}

private function OnSync(event:SyncEvent):void {
}

public function startGame():void {
	myuser.prepareCar();
	var roomOwner:User =  getUserByUsername(getRoomByRoomName(myuser.room).owner);	
	myopponent = getOpponent();
	if (myopponent==null) {
		Alert.show("no opponent found !");
	} else {
		if (roomOwner.username==myuser.username) {
			myuser.isRoomOwner = true;
		} else {
			myuser.isRoomOwner = false;
		}
		myopponent.isRoomOwner = !(myuser.isRoomOwner);
		myopponent.prepareCar();
	}	
	game.prepareStart();
}
public function joinRoom():void {
	var newRoom:String = rooms_list.selectedItem.name;
	if (myuser.room == newRoom) return;
	if (getRoomByRoomName(newRoom).isLocked) {
		Alert.show("room is full !");
		return;
	}	
	myuser.room = newRoom;
	connect();
}
public function gameOver(message:String):void {
	game.over(message);
	myuser.myCar.endRace();
}
public function connect():void {	
	var s:String = server + myuser.room;
	if (nc.connected) nc.close();
	users_dp.removeAll();
	rooms_dp.removeAll();
  	nc=new NetConnection();			
	nc.client=this;
	myuser.username = username_txt.text;
	nc.connect(s, myuser.id , myuser.username , myuser.room , myuser.sex , myuser.webcam);
	nc.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);
	so_chat = SharedObject.getRemote("chat", nc.uri,false);
	so_chat.client = this;
	so_chat.addEventListener(SyncEvent.SYNC, OnSync);
	so_chat.connect(nc);	
}

public function updateOppentCarPosition(username:String, x:Number,y:Number,speedX:Number,speedY:Number,rotation:Number):void {
	if (myuser.username==username) return;
	myopponent.myCar.oldSpeedX=(x-myopponent.myCar.x)/ myopponent.myCar.framesElapsedBetween2Synchs;
	myopponent.myCar.oldSpeedY=(y-myopponent.myCar.y)/ myopponent.myCar.framesElapsedBetween2Synchs;
	myopponent.myCar.rotation = rotation;
	//info_txt.text="frames elapsed:"+myopponent.myCar.framesElapsedBetween2Synchs;
	myopponent.myCar.framesElapsedBetween2Synchs=1;
}

private function removeInfo(e:CloseEvent):void { 
	this.removeChild(e.target as DisplayObject);
}

public function init():void {
	nc = new NetConnection();
	username_txt.text="guest"+ int(Math.random()*100);
	myuser = new User("0",username_txt.text,"m","lobby","false");		
	initBackground();
}
public function initBackground():void {
	gameCanvas.rawChildren.addChild(track1Limits);
	gameCanvas.rawChildren.addChild(track1);
	gameCanvas.rawChildren.addChild(track1DecoOver);
	
	track1Limits.checkpoint1.visible = false;
	track1Limits.checkpoint2.visible = false;
}

public function initKeyBoard():void {
	stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);
	stage.addEventListener(KeyboardEvent.KEY_UP,keyUpListener);
}
public function removeKeyBoard():void {
	stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);
	stage.removeEventListener(KeyboardEvent.KEY_UP,keyUpListener);
	myuser.myCar.downKey = myuser.myCar.upKey = myuser.myCar.leftKey = myuser.myCar.rightKey = myuser.myCar.spaceKey = false;
}
private function keyUpListener(e:KeyboardEvent):void {
	myuser.myCar.keyPressed = false;
	switch(e.keyCode) 	{
		case Keyboard.LEFT:
		myuser.myCar.leftKey = false;
		break;
		
		case Keyboard.UP:
		myuser.myCar.upKey = false;
		break;
		
		case Keyboard.RIGHT:
		myuser.myCar.rightKey = false;
		break;
		
		case Keyboard.DOWN:
		myuser.myCar.downKey = false;
		break;
		
		case Keyboard.SPACE:
		myuser.myCar.shoot();

		myuser.myCar.spaceKey = false;
		break;
		default:
		break;
	}
}

private function keyDownListener(e:KeyboardEvent):void {
	myuser.myCar.keyPressed = true;
	switch(e.keyCode){
		case Keyboard.LEFT:
		myuser.myCar.leftKey = true;
		break;
		
		case Keyboard.UP:
		myuser.myCar.upKey = true;
		break;
		
		case Keyboard.RIGHT:
		myuser.myCar.rightKey = true;
		break;
		
		case Keyboard.DOWN:
		myuser.myCar.downKey = true;
		break;
		
		case Keyboard.SPACE:
		myuser.myCar.spaceKey = true;
		break;
		
		default:
		break;
	}
}